home *** CD-ROM | disk | FTP | other *** search
- /* cfengine for GNU
-
- Copyright (C) 1995
- Free Software Foundation, Inc.
-
- This file is part of GNU cfengine - written and maintained
- by Mark Burgess, Dept of Computing and Engineering, Oslo College,
- Dept. of Theoretical physics, University of Oslo
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 2, or (at your option) any
- later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
-
- */
-
-
- /*********************************************************************/
- /* */
- /* TOOLKIT : Locks and Signals */
- /* */
- /*********************************************************************/
-
- /* A log file of the run times is kept for each host separately.
- This records each atomic lock and the time at which it
- completed, for use in computing the elapsed time. The file
- format is:
-
- %s time:operation:operand
-
- Each operation (independently of operand) has a "last" inode
- which keeps the time at which is last completed, for use in
- calculating IfElapsed. The idea here is that the elapsed time
- is from the time at which the last operation of this type
- FINISHED. This is different from a lock (which is used to
- allow several sub operations to coexist). Here we are
- limiting activity in general to avoid "spamming".
-
- Each atomic operation (including operand) has a lock. The
- removal of this lock causes the "last" file to be updated.
- This is used to actually prevent execution of an atom
- which is already being executed. If this lock has existed
- for longer than the ExpireAfter time, the process owning
- the lock is killed and the lock is re-established. The
- lock file contains the pid.
-
- This is robust to hanging locks and can be thought of as
- a garbage collection mechanism for these locks.
-
- Last files are just inodes (empty files) so they use no disk.
- The locks (which never exceed the no of running processes)
- contain the pid.
-
- */
-
- #include "cf.defs.h"
- #include "cf.extern.h"
-
- /* The locks need these in case of signals */
-
- char CFLOCK[bufsize];
- char CFLOG[bufsize];
- char CFLAST[bufsize];
-
- time_t GetLastLock();
- time_t CheckOldLock();
-
- /********************************************************************/
-
- void HandleSignal(signum)
-
- int signum;
-
- {
- sprintf(OUTPUT,"Received signal %s\n",SIGNALS[signum]);
- CfLog(cfinform,OUTPUT,"");
-
- if (signum == SIGTERM || signum == SIGINT || signum == SIGHUP)
- {
- ReleaseCurrentLock();
- closelog();
- exit(0);
- }
- }
-
- /************************************************************************/
-
- GetLock(operator,operand,ifelapsed,expireafter,host,now)
-
- char *operator, *operand, *host;
- int ifelapsed, expireafter;
- time_t now;
-
- { struct stat statbuf;
- unsigned int pid;
- time_t lastcompleted = 0, elapsedtime;
-
- if (IGNORELOCK)
- {
- return true;
- }
-
- if (now == 0)
- {
- if ((now = time((time_t *)NULL)) == -1)
- {
- printf("Couldn't read system clock\n");
- }
- return true;
- }
-
- Debug("GetLock(%s,%s,time=%d), ExpireAfter=%d, IfElapsed=%d\n",operator,operand,now,expireafter,ifelapsed);
-
- sprintf(CFLOG,"%s/cfengine.%s.runlog",VLOGDIR,host);
- sprintf(CFLOCK,"%s/lock.%s.%s.%s.%s",VLOCKDIR,VCANONICALFILE,host,operator,operand);
- sprintf(CFLAST,"%s/last.%s.%s.%s.%s",VLOCKDIR,VCANONICALFILE,host,operator,operand);
-
- if (strlen(CFLOCK) > 254)
- {
- CFLOCK[253] = '\0'; /* most nodenames are 255 chars or less */
- }
-
- if (strlen(CFLAST) > 254)
- {
- CFLAST[253] = '\0'; /* most nodenames are 255 chars or less */
- }
-
- /* Look for non-existent (old) processes */
-
- lastcompleted = GetLastLock();
- elapsedtime = (time_t)(now-lastcompleted) / 60;
-
- if (elapsedtime < 0)
- {
- sprintf(OUTPUT,"Another cfengine seems to have done %s.%s since I started\n",operator, operand);
- CfLog(cfverbose,OUTPUT,"");
- return false;
- }
-
- if (elapsedtime < ifelapsed)
- {
- sprintf(OUTPUT,"Too soon since last run with %s.%s (%u/%u minutes)\n",operator,operand,elapsedtime,ifelapsed);
- CfLog(cfverbose,OUTPUT,"");
- return false;
- }
-
- /* Look for existing (current) processes */
-
- lastcompleted = CheckOldLock();
- elapsedtime = (time_t)(now-lastcompleted) / 60;
-
- if (lastcompleted != 0)
- {
- if (elapsedtime >= expireafter)
- {
- sprintf(OUTPUT,"Lock %s expired...(after %u/%u minutes)\n",CFLOCK,elapsedtime,expireafter);
- CfLog(cfinform,OUTPUT,"");
-
- pid = GetLockPid();
-
- if (pid == -1)
- {
- sprintf(OUTPUT,"Illegal pid in corrupt lock %s - ignoring lock\n",CFLOCK);
- CfLog(cferror,OUTPUT,"");
- }
- else
- {
- Verbose("Trying to kill expired cfengine\n");
- kill(pid,SIGCONT);
- sleep(3);
- kill(pid,SIGINT);
- sleep(1);
- kill(pid,SIGTERM);
- sleep(5);
- kill(pid,SIGKILL);
- sleep(1);
-
- if (kill(pid,SIGTERM) == ESRCH)
- {
- sprintf(OUTPUT,"Unable to kill expired process %d, exiting this time..\n",pid);
- CfLog(cferror,OUTPUT,"");
- FatalError("");;
- }
-
- LockLog(pid,"Lock expired, process killed",operator,operand);
- }
-
- unlink(CFLOCK);
- }
- else
- {
- Verbose("Couldn't obtain lock for %s (already running!)\n",CFLOCK);
- return false;
- }
- }
-
- SetLock();
- return true;
- }
-
- /************************************************************************/
-
- ReleaseCurrentLock()
-
- { int fd;
-
- if (IGNORELOCK)
- {
- return;
- }
-
- Debug("ReleaseCurrentLock(%s)\n",CFLOCK);
-
- if (unlink(CFLOCK) == -1)
- {
- sprintf(OUTPUT,"Unable to remove lock %s\n",CFLOCK);
- CfLog(cflogonly,OUTPUT,"unlink");
- return;
- }
-
- if ((fd = creat(CFLAST,0644)) == -1)
- {
- sprintf(OUTPUT,"Unable to create %s\n",CFLAST);
- CfLog(cferror,OUTPUT,"creat");
- FatalError("");
- }
- else
- {
- close(fd);
- }
-
- LockLog(getpid(),"Lock removed normally",CFLOCK,"");
- }
-
-
- /************************************************************************/
-
- CountActiveLocks(now)
-
- /* Count the number of active locks == number of cfengines running */
-
- time_t now;
-
- { DIR *dirh;
- struct dirent *dirp;
- int count = 0;
-
- if ((dirh = opendir(VLOCKDIR)) == NULL)
- {
- sprintf(OUTPUT,"Can't open directory %s\n",VLOCKDIR);
- CfLog(cferror,OUTPUT,"opendir");
- return 0;
- }
-
- for (dirp = readdir(dirh); dirp != NULL; dirp = readdir(dirh))
- {
- if (strncmp(dirp->d_name,"lock",4) == 0)
- {
- count++;
- }
- }
-
- closedir(dirh);
-
- return count;
- }
-
- /************************************************************************/
- /* Level 2 */
- /************************************************************************/
-
- time_t GetLastLock()
-
- { struct stat statbuf;
- int fd;
-
- bzero(&statbuf,sizeof(statbuf));
-
- Debug("GetLastLock()\n");
-
- if (stat(CFLAST,&statbuf) == -1)
- {
-
- /* Do this to prevent deadlock loops from surviving if IfElapsed > T_sched */
-
- if ((fd = creat(CFLAST,0644)) == -1)
- {
- sprintf(OUTPUT,"Unable to create %s\n",CFLAST);
- CfLog(cferror,OUTPUT,"creat");
- FatalError("");
- }
- else
- {
- close(fd);
- }
- return 0;
- }
- else
- {
- return statbuf.st_mtime;
- }
- }
-
- /************************************************************************/
-
- time_t CheckOldLock()
-
- { struct stat statbuf;
-
- bzero(&statbuf,sizeof(statbuf));
-
- Debug("CheckOldLock()\n");
-
- if (stat(CFLOCK,&statbuf) == -1)
- {
- return 0;
- }
- else
- {
- return statbuf.st_mtime;
- }
- }
-
- /************************************************************************/
-
- GetLockPid()
-
- { FILE *fp;
- int pid = -1;
-
- if ((fp = fopen(CFLOCK,"r")) == NULL)
- {
- CfLog(cferror,"GetLock weird error, lock disappeared!\n","fopen");
- FatalError("");
- }
-
- fscanf(fp,"%d",&pid);
-
- fclose(fp);
-
- return pid;
- }
-
- /************************************************************************/
-
- SetLock()
-
- { FILE *fp;
-
- Debug("SetLock(%s)\n",CFLOCK);
-
- if ((fp = fopen(CFLOCK,"w")) == NULL)
- {
- sprintf(OUTPUT,"GetLock: can't open new lock file %s\n",CFLOCK);
- CfLog(cferror,OUTPUT,"fopen");
- FatalError("");;
- }
-
- fprintf(fp,"%d\n",getpid());
-
- fclose(fp);
- chmod(CFLOCK,0644);
- }
-
- /************************************************************************/
-
- LockLog(pid,str,operator,operand)
-
- int pid;
- char *str, *operator, *operand;
-
- { FILE *fp;
- char buffer[maxvarsize];
- struct stat statbuf;
- time_t tim;
-
- Debug("LockLog(%s)\n",str);
-
- if ((fp = fopen(CFLOG,"a")) == NULL)
- {
- sprintf(OUTPUT,"GetLock: can't open log file %s\n",CFLOG);
- CfLog(cferror,OUTPUT,"fopen");
- FatalError("");
- }
-
- if ((tim = time((time_t *)NULL)) == -1)
- {
- Debug("Cfengine: couldn't read system clock\n");
- }
-
- sprintf(buffer,"%s",ctime(&tim));
-
- Chop(buffer);
-
- fprintf(fp,"%s:%s:pid=%d:%s:%s\n",buffer,str,pid,operator,operand);
-
- fclose(fp);
-
- if (stat(CFLOG,&statbuf) != -1)
- {
- if (statbuf.st_size > CFLOGSIZE)
- {
- Verbose("Rotating lock-runlog file\n");
- RotateFiles(CFLOG,2);
- }
- }
- }
-
-